import {Message} from '@/interface/websocket/entity/SocketMessage';
import Cache from '@/utils/Cache';

let socket: WebSocket;
const cache = new Cache();

/**
 * websocket 连接配置
 */
interface WebsocketConfig {
  // websocket 地址
  url: string
  // 重连时间
  reconnectTime: number
  // 心跳时间
  heartTime: number,
  // 延时发送
  waitSend?: number,
  // 监听 message 回调事件
  onMessage?: (event) => void
  // 监听 open 回调事件
  onOpen?: (event) => void
  // 监听 error 回调事件
  onError?: (event) => void
  // 监听 close 回调事件
  onClose?: (event) => void
}

class Websocket {
  socketConfig: WebsocketConfig;

  constructor(config: WebsocketConfig) {
    this.socketConfig = config;
  }

  create = () => {
    let config: WebsocketConfig = this.socketConfig;
    let socketUrl = config.url;
    let lockReconnect = false;
    let timer: ReturnType<typeof setTimeout>;
    /**
     * 创建 socket 连接
     */
    const createSocket = () => {
      try {
        socket = new WebSocket(socketUrl);
        socketInit()
      } catch (e) {
        console.error(e);
        reconnect();
      }
    }
    /**
     * 重连机制
     */
    const reconnect = () => {
      if (lockReconnect) {
        return;
      }
      lockReconnect = true;
      clearTimeout(timer);
      timer = setTimeout(() => {
        createSocket();
      }, config.reconnectTime);
    }
    /**
     * 初始化
     */
    const socketInit = () => {
      // 开启连接
      socket.onopen = function (e) {
        // console.info('websocket 成功连接');
        if (config.onOpen) {
          config.onOpen.call(null, e);
        }
      };
      // 接收消息回调方法
      socket.onmessage = function (e) {
        // console.info('websocket 接收到信息', e.data);
        // const heart = JSON.parse(e.data).type == -3;
        if (config.onMessage) {
          config.onMessage.call(null, e);
        }
        heartCheck.reset().start();
      };
      // 连接发生错误的回调方法
      socket.onerror = function (e) {
        console.error("websocket 发生错误");
        if (config.onError) {
          config.onError.call(null, e);
        }
        reconnect();
      };
      // 连接关闭的回调方法
      socket.onclose = function (e) {
        // console.warn("websocket 已关闭");
        if (config.onClose) {
          config.onClose.call(null, e);
        }
        // 心跳检测
        heartCheck.reset();
        reconnect();
      };

      // 监听窗口关闭事件，当窗口关闭时，主动去关闭websocket连接，防止连接还没断开就关闭窗口，server端会抛异常。
      window.onbeforeunload = function () {
        socket.close();
      };
    }
    /**
     * 心跳检测
     */
    const heartCheck = {
      timeout: config.heartTime,
      timeoutObj: setTimeout(() => {
        // .. 延迟消息
      }),
      serverTimeoutObj: setInterval(() => {
        // .. 服务器延迟消息
      }),
      // 重置消息心跳检测
      reset: function () {
        clearTimeout(this.timeoutObj);
        clearTimeout(this.serverTimeoutObj);
        return this;
      },
      // 开始心跳检测
      start: function () {
        let that = this;
        clearTimeout(this.timeoutObj);
        clearTimeout(this.serverTimeoutObj);
        this.timeoutObj = setTimeout(function () {
          // 这里发送一个心跳，后端收到后，返回一个心跳消息，
          // onmessage 拿到返回的心跳就说明连接正常
          socket.send(JSON.stringify({
            'type': -3
          }));
          // console.log('heart ping server');

          // 如果超过一定时间还没重置，说明后端主动断开了
          that.serverTimeoutObj = setTimeout(function () {
            // console.log('服务器关闭服务');
            //如果 onclose 会执行 reconnect，我们执行 websocket.close() 就行了.如果直接执行 reconnect 会触发 onclose 导致重连两次
            socket.close();
          }, that.timeout)
        }, this.timeout)
      }
    };
    // 创建 socket
    createSocket();
  }

  send = (msg: Message) => {
    if (socket != null && socket.readyState === 1) {
      socket.send(JSON.stringify(msg));
    } else if (socket == null) {
      console.error('socket is null');
    } else if (socket.readyState === 0) {
      // 延时发送
      setTimeout(function () {
        socket.send(JSON.stringify(msg));
      }, this.socketConfig.waitSend ? this.socketConfig.waitSend : 3000);
    }
  }
}

/*const create = (config: WebsocketConfig) => {
  let socketUrl = config.url;
  let lockReconnect = false;
  let timer: ReturnType<typeof setTimeout>;
  /!**
   * 创建 socket 连接
   *!/
  const createSocket = () => {
    try {
      socket = new WebSocket(socketUrl);
      socketInit()
    } catch (e) {
      console.error(e);
      reconnect();
    }
  }
  /!**
   * 重连机制
   *!/
  const reconnect = () => {
    if (lockReconnect) {
      return;
    }
    lockReconnect = true;
    clearTimeout(timer);
    timer = setTimeout(() => {
      createSocket();
    }, config.reconnectTime);
  }
  /!**
   * 初始化
   *!/
  const socketInit = () => {
    // 开启连接
    socket.onopen = function (e) {
      console.info('websocket 成功连接');
      if (config.onOpen) {
        config.onOpen.call(null, e);
      }
    };
    // 接收消息回调方法
    socket.onmessage = function (e) {
      console.info('websocket 接收到信息', e.data);
      const heart = /heart-pong/.test(e.data);
      if (config.onMessage && !heart) {
        config.onMessage.call(null, e);
      }
      heartCheck.reset().start();
    };
    // 连接发生错误的回调方法
    socket.onerror = function (e) {
      console.error("websocket 发生错误");
      if (config.onError) {
        config.onError.call(null, e);
      }
      reconnect();
    };

    // 连接关闭的回调方法
    socket.onclose = function (e) {
      console.warn("websocket 已关闭");
      if (config.onClose) {
        config.onClose.call(null, e);
      }
      // 心跳检测
      heartCheck.reset();
      reconnect();
    };

    // 监听窗口关闭事件，当窗口关闭时，主动去关闭websocket连接，防止连接还没断开就关闭窗口，server端会抛异常。
    window.onbeforeunload = function () {
      socket.close();
    };
  }
  /!**
   * 心跳检测
   *!/
  const heartCheck = {
    timeout: config.heartTime,
    timeoutObj: setTimeout(() => {
      // .. 延迟消息
    }),
    serverTimeoutObj: setInterval(() => {
      // .. 服务器延迟消息
    }),
    // 重置消息心跳检测
    reset: function () {
      clearTimeout(this.timeoutObj);
      clearTimeout(this.serverTimeoutObj);
      return this;
    },
    // 开始心跳检测
    start: function () {
      let that = this;
      clearTimeout(this.timeoutObj);
      clearTimeout(this.serverTimeoutObj);
      this.timeoutObj = setTimeout(function () {
        // 这里发送一个心跳，后端收到后，返回一个心跳消息，
        // onmessage 拿到返回的心跳就说明连接正常
        socket.send(JSON.stringify({
          'type': -3
        }));
        console.log('heart ping server');

        // 如果超过一定时间还没重置，说明后端主动断开了
        that.serverTimeoutObj = setTimeout(function () {
          console.log('服务器关闭服务');
          //如果 onclose 会执行 reconnect，我们执行 websocket.close() 就行了.如果直接执行 reconnect 会触发 onclose 导致重连两次
          socket.close();
        }, that.timeout)
      }, this.timeout)
    }
  };
  // 创建 socket
  createSocket();
}*/

/*const send = (msg: object | string | number) => {
  if (socket != null) {
    socket.send(JSON.stringify(msg));
  } else {
    console.error('socket is null');
  }
}*/

export {Websocket, WebsocketConfig}
